use rocket::request::{FromRequest, Outcome};
use rocket::Request;
use std::collections::HashMap;
use rocket_okapi::okapi::schemars;
use rocket_okapi::okapi::schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};

/// A structure to hold request headers.
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct RequestHeaders {
    pub headers: HashMap<String, String>,
}

impl RequestHeaders {
    /// Try to create a RequestHeaders instance from an Rocket Request.
    pub fn try_from_request(req: &Request) -> Outcome<Self, String> {
        let mut headers = HashMap::new();

        for header in req.headers().iter() {
            let key = header.name().to_string();
            let value = header.value().to_string(); // Use to_string() to get the header value
            headers.insert(key, value);
        }

        Outcome::Success(RequestHeaders { headers })
    }

    /// Get the value of a header.
    pub fn get(&self, key: &str) -> Option<&String> {
        self.headers.get(key)
    }

    /// Check if a header exists.
    pub fn contains_key(&self, key: &str) -> bool {
        self.headers.contains_key(key)
    }

    /// Remove a header.
    pub fn remove(&mut self, key: &str) -> Option<String> {
        self.headers.remove(key)
    }

    /// Insert a new header.
    pub fn insert(&mut self, key: String, value: String) -> Option<String> {
        self.headers.insert(key, value)
    }

    /// List all headers.
    pub fn list(&self) -> &HashMap<String, String> {
        &self.headers
    }

    /// Print all headers in a formatted way.
    pub fn print(&self) {
        let formatted_headers: String = self.headers.iter()
            .map(|(key, value)| format!("  {}: {}", key, value))
            .collect::<Vec<String>>()
            .join("\n");
        log::info!("\nRequest Headers:\n{}", formatted_headers);
    }
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for RequestHeaders {
    type Error = String;

    async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
        RequestHeaders::try_from_request(req)
    }
}
